home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
gnu
/
cvs-1_3.lha
/
cvs-1.3
/
src
/
rtag.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-09
|
10KB
|
404 lines
/*
* Copyright (c) 1992, Brian Berliner and Jeff Polk
* Copyright (c) 1989-1992, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License as
* specified in the README file that comes with the CVS 1.3 kit.
*
* Rtag
*
* Add or delete a symbolic name to an RCS file, or a collection of RCS files.
* Uses the modules database, if necessary.
*/
#include "cvs.h"
#ifndef lint
static char rcsid[] = "@(#)rtag.c 1.57 92/04/10";
#endif
#if __STDC__
static Dtype rtag_dirproc (char *dir, char *repos, char *update_dir);
static int rtag_fileproc (char *file, char *update_dir,
char *repository, List * entries,
List * srcfiles);
static int rtag_proc (int *pargc, char *argv[], char *xwhere,
char *mwhere, char *mfile, int shorten,
int local_specified, char *mname, char *msg);
static int rtag_delete (RCSNode *rcsfile);
#else
static int rtag_proc ();
static int rtag_fileproc ();
static Dtype rtag_dirproc ();
static int rtag_delete ();
#endif /* __STDC__ */
static char *symtag;
static char *numtag;
static int delete; /* adding a tag by default */
static int attic_too; /* remove tag from Attic files */
static int branch_mode; /* make an automagic "branch" tag */
static char *date;
static int local; /* recursive by default */
static int force_tag_match = 1; /* force by default */
static char *rtag_usage[] =
{
"Usage: %s %s [-QaflRnq] [-b] [-d] [-r tag|-D date] tag modules...\n",
"\t-Q\tReally quiet.\n",
"\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
"\t-f\tForce a head revision match if tag/date not found.\n",
"\t-l\tLocal directory only, not recursive\n",
"\t-R\tProcess directories recursively.\n",
"\t-n\tNo execution of 'tag program'\n",
"\t-q\tSomewhat quiet.\n",
"\t-d\tDelete the given Tag.\n",
"\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
"\t-[rD]\tExisting tag or Date.\n",
NULL
};
int
rtag (argc, argv)
int argc;
char *argv[];
{
register int i;
int c;
DBM *db;
int run_module_prog = 1;
int err = 0;
if (argc == -1)
usage (rtag_usage);
optind = 1;
while ((c = gnu_getopt (argc, argv, "anfQqlRdbr:D:")) != -1)
{
switch (c)
{
case 'a':
attic_too = 1;
break;
case 'n':
run_module_prog = 0;
break;
case 'Q':
really_quiet = 1;
/* FALL THROUGH */
case 'q':
quiet = 1;
break;
case 'l':
local = 1;
break;
case 'R':
local = 0;
break;
case 'd':
delete = 1;
break;
case 'f':
force_tag_match = 0;
break;
case 'b':
branch_mode = 1;
break;
case 'r':
numtag = optarg;
break;
case 'D':
if (date)
free (date);
date = Make_Date (optarg);
break;
case '?':
default:
usage (rtag_usage);
break;
}
}
argc -= optind;
argv += optind;
if (argc < 2)
usage (rtag_usage);
symtag = argv[0];
argc--;
argv++;
if (date && numtag)
error (1, 0, "-r and -D options are mutually exclusive");
if (delete && branch_mode)
error (0, 0, "warning: -b ignored with -d options");
RCS_check_tag (symtag);
db = open_module ();
for (i = 0; i < argc; i++)
{
/* XXX last arg should be repository, but doesn't make sense here */
history_write ('T', (delete ? "D" : (numtag ? numtag :
(date ? date : "A"))), symtag, argv[i], "");
err += do_module (db, argv[i], TAG, delete ? "Untagging" : "Tagging",
rtag_proc, (char *) NULL, 0, 0, run_module_prog,
symtag);
}
close_module (db);
return (err);
}
/*
* callback proc for doing the real work of tagging
*/
/* ARGSUSED */
static int
rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified,
mname, msg)
int *pargc;
char *argv[];
char *xwhere;
char *mwhere;
char *mfile;
int shorten;
int local_specified;
char *mname;
char *msg;
{
int err = 0;
int which;
char repository[PATH_MAX];
char where[PATH_MAX];
(void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
(void) strcpy (where, argv[0]);
/* if mfile isn't null, we need to set up to do only part of the module */
if (mfile != NULL)
{
char *cp;
char path[PATH_MAX];
/* if the portion of the module is a path, put the dir part on repos */
if ((cp = rindex (mfile, '/')) != NULL)
{
*cp = '\0';
(void) strcat (repository, "/");
(void) strcat (repository, mfile);
(void) strcat (where, "/");
(void) strcat (where, mfile);
mfile = cp + 1;
}
/* take care of the rest */
(void) sprintf (path, "%s/%s", repository, mfile);
if (isdir (path))
{
/* directory means repository gets the dir tacked on */
(void) strcpy (repository, path);
(void) strcat (where, "/");
(void) strcat (where, mfile);
}
else
{
int i;
/* a file means muck argv */
for (i = 1; i < *pargc; i++)
free (argv[i]);
argv[1] = xstrdup (mfile);
(*pargc) = 2;
}
}
/* chdir to the starting directory */
if (chdir (repository) < 0)
{
error (0, errno, "cannot chdir to %s", repository);
return (1);
}
if (delete || attic_too || (force_tag_match && numtag))
which = W_REPOS | W_ATTIC;
else
which = W_REPOS;
/* start the recursion processor */
err = start_recursion (rtag_fileproc, (int (*) ()) NULL, rtag_dirproc,
(int (*) ()) NULL, *pargc - 1, argv + 1, local,
which, 0, 1, where, 1);
return (err);
}
/*
* Called to tag a particular file, as appropriate with the options that were
* set above.
*/
/* ARGSUSED */
static int
rtag_fileproc (file, update_dir, repository, entries, srcfiles)
char *file;
char *update_dir;
char *repository;
List *entries;
List *srcfiles;
{
Node *p;
RCSNode *rcsfile;
char *version, *rev;
int retcode = 0;
/* find the parsed RCS data */
p = findnode (srcfiles, file);
if (p == NULL)
return (1);
rcsfile = (RCSNode *) p->data;
/*
* For tagging an RCS file which is a symbolic link, you'd best be
* running with RCS 5.6, since it knows how to handle symbolic links
* correctly without breaking your link!
*/
if (delete)
return (rtag_delete (rcsfile));
/*
* If we get here, we are adding a tag. But, if -a was specified, we
* need to check to see if a -r or -D option was specified. If neither
* was specified and the file is in the Attic, remove the tag.
*/
if (attic_too && (!numtag && !date))
{
if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
return (rtag_delete (rcsfile));
}
version = RCS_getversion (rcsfile, numtag, date, force_tag_match);
if (version == NULL)
{
/* If -a specified, clean up any old tags */
if (attic_too)
(void) rtag_delete (rcsfile);
if (!quiet && !force_tag_match)
{
error (0, 0, "cannot find tag `%s' in `%s'",
numtag ? numtag : "head", rcsfile->path);
return (1);
}
return (0);
}
if (numtag && isdigit (*numtag) && strcmp (numtag, version) != 0)
{
/*
* We didn't find a match for the numeric tag that was specified, but
* that's OK. just pass the numeric tag on to rcs, to be tagged as
* specified. Could get here if one tried to tag "1.1.1" and there
* was a 1.1.1 branch with some head revision. In this case, we want
* the tag to reference "1.1.1" and not the revision at the head of
* the branch. Use a symbolic tag for that.
*/
rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, numtag);
}
else
{
char *oversion;
/*
* As an enhancement for the case where a tag is being re-applied to
* a large body of a module, make one extra call to Version_Number to
* see if the tag is already set in the RCS file. If so, check to
* see if it needs to be moved. If not, do nothing. This will
* likely save a lot of time when simply moving the tag to the
* "current" head revisions of a module -- which I have found to be a
* typical tagging operation.
*/
oversion = RCS_getversion (rcsfile, symtag, (char *) 0, 1);
if (oversion != NULL)
{
if (strcmp (version, oversion) == 0)
{
free (version);
free (oversion);
return (0);
}
free (oversion);
}
rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, rev);
}
run_arg (rcsfile->path);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
{
if (!quiet)
error (0, retcode == -1 ? errno : 0,
"failed to set tag `%s' to revision `%s' in `%s'",
symtag, rev, rcsfile->path);
free (version);
return (1);
}
free (version);
return (0);
}
/*
* If -d is specified, "force_tag_match" is set, so that this call to
* Version_Number() will return a NULL version string if the symbolic
* tag does not exist in the RCS file.
*
* If the -r flag was used, numtag is set, and we only delete the
* symtag from files that have numtag.
*
* This is done here because it's MUCH faster than just blindly calling
* "rcs" to remove the tag... trust me.
*/
static int
rtag_delete (rcsfile)
RCSNode *rcsfile;
{
char *version;
int retcode;
if (numtag)
{
version = RCS_getversion (rcsfile, numtag, (char *) 0, 1);
if (version == NULL)
return (0);
free (version);
}
version = RCS_getversion (rcsfile, symtag, (char *) 0, 1);
if (version == NULL)
return (0);
free (version);
run_setup ("%s%s -q -N%s", Rcsbin, RCS, symtag);
run_arg (rcsfile->path);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) != 0)
{
if (!quiet)
error (0, retcode == -1 ? errno : 0,
"failed to remove tag `%s' from `%s'", symtag,
rcsfile->path);
return (1);
}
return (0);
}
/*
* Print a warm fuzzy message
*/
/* ARGSUSED */
static Dtype
rtag_dirproc (dir, repos, update_dir)
char *dir;
char *repos;
char *update_dir;
{
if (!quiet)
error (0, 0, "%s %s", delete ? "Untagging" : "Tagging", update_dir);
return (R_PROCESS);
}